# -*- coding: UTF-8 -*-

'''
Created on 03.02.2013

@author: Peter Heß, Germany

samples from vvvv how they do it:

Centered/-/-/Phase=.50/Count=11
0.0455, 0.1364, 0.2273, 0.3182, 0.4091, -0.5000, -0.4091, -0.3182, -0.2273, -0.1364, -0.0455

Centered/-/-/Phase=.75/Count=11
0.2955, 0.3864, 0.4773, -0.4318, -0.3409, -0.2500, -0.1591, -0.0682, 0.0227, 0.1136, 0.2045

'''

import numpy as np
import objects3d.BuildingBlockBase as bbb
import math as m
class CircularSpread(bbb.BuildingBlockBase):
    '''
    '''

    def __init__(self, InputX_in=[0.0],
                        InputY_in=[0.0],
                        Width_in=[1.0],
                        Height_in=[1.0],
                        Factor_in=[1.0],
                        Phase_in=[0.0],
                        SpreadCount_in=[0]):
        
        bbb.BuildingBlockBase.__init__(self)  # setup some basic variables like dirty etc...

        self.InputX_in = InputX_in
        self.InputY_in = InputY_in
        self.Width_in = Width_in
        self.Height_in = Height_in
        self.Factor_in = Factor_in
        self.Phase_in = Phase_in
        self.SpreadCount_in = SpreadCount_in
        self.OutputX = None
        self.OutputY = None

    def update(self, InputX_in=None,
                     InputY_in=None,
                     Width_in=None,
                     Height_in=None,
                     Factor_in=None,
                     Phase_in=None,
                     SpreadCount_in=None):
        
        if InputX_in != None and self.InputX_in != InputX_in :
            self.InputX_in = InputX_in
            self.Dirty = True
        if (InputY_in != None and self.InputY_in != InputY_in): 
            self.InputY_in = InputY_in
            self.Dirty = True
        if (Width_in != None and self.Width_in != Width_in): 
            self.Width_in = Width_in
            self.Dirty = True
        if (Height_in != None and self.Height_in != Height_in): 
            self.Height_in = Height_in
            self.Dirty = True
        if (Factor_in != None and self.Factor_in != Factor_in):
            self.Factor_in = Factor_in
            self.Dirty = True
        if (Phase_in != None and self.Phase_in != Phase_in):
            self.Phase_in = Phase_in  # convert phase value to radians
            self.Dirty = True
        if (SpreadCount_in != None and self.SpreadCount_in != SpreadCount_in):
            self.SpreadCount_in = SpreadCount_in
            self.Dirty = True

        if (not self.Dirty) :  # if nothing changed on input, we must do nothing
            return
        
        self.dirty = False;  # reset dirty for the next call to update

        # compute the number of rows needed for all spreads 
        p = np.array([len(self.InputX_in),
                      len(self.InputY_in),
                      len(self.Width_in),
                      len(self.Height_in),
                      len(self.Factor_in),
                      len(self.Phase_in),
                      len(self.SpreadCount_in)])
        self.maxcount = p.max() 
        # if there are not data, eg. after the initialisation of the object no work must be done
        if self.maxcount == 0:
            self.output = np.array()
            return;
        
        r = range(self.maxcount)
        # The in variables are not used during processing. Only their "non" in counterpards
        self.InputX = np.arange(self.maxcount, dtype=np.float)
        self.InputY = np.arange(self.maxcount, dtype=np.float)
        self.Width = np.arange(self.maxcount, dtype=np.float)
        self.Height = np.arange(self.maxcount, dtype=np.float)
        self.Factor = np.arange(self.maxcount, dtype=np.float)
        self.Phase = np.arange(self.maxcount, dtype=np.float)
        self.SpreadCount = np.arange(self.maxcount, dtype=np.float)

        # intern we need a int value for SpreadCount
        self.SpreadCount = self.SpreadCount.astype(int) 
        
        # removeme self.MaxValSpread = np.arange(self.maxcount, dtype=np.float)
        # removeme self.MinValSpread = np.arange(self.maxcount, dtype=np.float)

        # fill the internal spreads. If a output is too short for maxcount
        # it's internal data is wrapped and replicated until the output
        # has the lenght of maxcount
        np.put(self.InputX, r, self.InputX_in)
        np.put(self.InputY, r, self.InputY_in)
        np.put(self.Width, r, self.Width_in)
        np.put(self.Height, r, self.Height_in)
        np.put(self.Factor, r, self.Factor_in)
        self.Factor = self.Factor

        # compute the phase shifting for values
        np.put(self.Phase, r, self.Phase_in)  # phase = float(0..1)
        angleOfCurrentPhase = np.mod(np.abs(self.Phase), 1) * 360  # angleOfCurrentPhase float = (0..359.99999)
        self.Phase = np.radians(angleOfCurrentPhase)  # from here all values of self.Phase are in radians
        
        np.put(self.SpreadCount, r, self.SpreadCount_in)

        # print "self.Width:", self.Width, "\r"
        # print "self.Phase:", self.Phase, "\r"
        
        # compute the max. values of the circle
        maxx = np.divide(self.Width, 2)
        maxy = np.divide(self.Height, 2)

        self.OutputX = []
        self.OutputY = []

        factored = self.Factor * 360.0

        for i in r:  # loops over the spreads (virtual rows...)

            # reset vars for each loop

            # now we must split the circle into several seqments
            spreadc = self.SpreadCount[i];
            if spreadc <= 0 :  
                continue  # nothing to do, if no spreadcound is needed

            segInDegrees = 0.0
            outputListX = np.arange(spreadc, dtype=np.float)
            outputListY = np.arange(spreadc, dtype=np.float)
            
            segAngleInDegrees = factored[i] / spreadc  # compute the seqment angle for each step
            
            for a in range(spreadc):  # compute value for each segment (the spreadcount)
                p = self.Phase[i] + m.radians(segInDegrees)
                outputListX[a] = m.cos(p) * maxx[i]
                outputListY[a] = m.sin(p) * maxy[i]
                segInDegrees += segAngleInDegrees  # prepare next seqment
                
            # end of for a
            
            # add x,y shift to all values
            outputListX = outputListX + self.InputX[i]              
            outputListY = outputListY + self.InputY[i]
            
            # append result of this loop to total result list
            self.OutputX.extend(outputListX.tolist())
            self.OutputY.extend(outputListY.tolist())
        # end of for i

        return
    
    def dump(self):
        print ("self.InputX=" + self.InputX,
               " self.InputY=" + self.InputY + " self.Width=" + self.Width,
               " self.Height=" + self.Height + " self.Factor=" + self.Factor + 
               " self.Phase=" + self.Phase + " self.SpreadCount=" + self.SpreadCount + "\r")
    
